//
// (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com)
// All rights reserved.
//

/* Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using EffiProz.Core.Lib;
using EffiProz.Core.DataTypes;
using EffiProz.Core.Resources;


namespace EffiProz.Core.DbInfos
{
    /**
     * Provides information intrinsic to each standard data type known to
     * HSQLDB.  This includes all types for which standard type codes are known
     * at the time of writing and thus includes types that may not yet be
     * supported as table or procedure columns. <p>
     *
     * @author  boucherb@users
     * @version 1.8.0
     * @since 1.7.2
     */
    sealed class DITypeInfo
    {

        // related to DatabaseMetaDataValues
        public const int columnNoNulls = 0;
        public const int columnNullable = 1;
        public const int typePredNone = 0;
        public const int typePredChar = 1;
        public const int typePredBasic = 2;
        public const int typeSearchable = 3;

        /** BundleHandler id for create params resource bundle. */
        private int hnd_create_params = -1;

        /** BundleHandler id for local names resource bundle. */
        private int hnd_local_names = -1;

        /** BundleHandler id for data type remarks resource bundle. */
        private int hnd_remarks = -1;

        /** The SQL type code on which this object is reporting. */
        private int type = Types.SQL_ALL_TYPES;

        /** The HSQLDB subtype code on which this object is reporting. */
        private int typeSub = Types.TYPE_SUB_DEFAULT;
        public bool locale_set;

        /** Creates a new DITypeInfo object having the default Locale. */
        public DITypeInfo()
        {

            // boucherb@users 20050515 - patch 1.8.0 - make setLocale lazy
            //setLocale(Locale.getDefault());
        }

        /**
         * Retrieves the maximum int.MaxValue bounded length, _in bytes, for
         * character types. <p>
         *
         * @return the maximum int.MaxValue bounded length, in
         *    bytes, for character types
         */
        public int? getCharOctLen()
        {
            return null;
        }

        /**
         * Retrieves the maximum long.MaxValue bounded length, _in bytes, for
         * character types. <p>
         *
         * @return the maximum long.MaxValue bounded length, in
         *    bytes, for character types
         */
        public long? getCharOctLenAct()
        {

            switch (type)
            {

                case Types.SQL_CHAR:
                case Types.SQL_NCHAR:
                case Types.SQL_VARCHAR:
                case Types.SQL_NVARCHAR:
                    return (2L * int.MaxValue);

                case Types.SQL_CLOB:
                case Types.NCLOB:
                    return (long.MaxValue);

                default:
                    return null;
            }
        }

        /**
         * Retrieves the fully-qualified name of the Java class whose instances
         * are manufactured by HSQLDB to store table column values in
         * memory. <p>
         *
         * This is also typically the fully-qualified name of the Java class whose
         * instances are manufactured by HSQLDB _in response to
         * jdbcResultSet.getObject(int). <p>
         *
         * @return the fully-qualified name of the Java class whose
         *    instances are manufactured by HSQLDB to store
         *    table column values _in memory
         */
        public string getColStClsName()
        {
            return Types.getColStClsName(type);
        }

        /**
         * Retrieves a character sequence representing a CSV list, in
         * DDL declaraion order, of the create parameters for the type. <p>
         *
         * @return a character sequence representing a CSV
         *    list, _in DDL declaraion order, of the create
         *    parameters for the type.
         */
        public string getCreateParams()
        {

            if (!locale_set)
            {
                setLocale(System.Globalization.CultureInfo.CurrentCulture);
            }

            string names;

            switch (type)
            {

                case Types.SQL_BINARY:
                case Types.SQL_CHAR:
                case Types.SQL_NCHAR:
                case Types.SQL_CLOB:
                case Types.NCLOB:
                case Types.SQL_VARBINARY:
                case Types.SQL_VARCHAR:
                case Types.SQL_NVARCHAR:
                    names = "LENGTH";
                    break;

                case Types.SQL_DECIMAL:
                case Types.SQL_NUMERIC:
                    names = "PRECISION,SCALE";
                    break;

                case Types.SQL_FLOAT:
                case Types.SQL_TIMESTAMP:
                    names = "PRECISION";
                    break;

                default:
                    names = null;
                    break;
            }

            return names;
        }

        /**
         * Retrieves the fully-qualified name of the HSQLDB-provided java.sql
         * interface implementation class whose instances would be manufactured
         * by HSQLDB to retrieve column values of this type, if the
         * the type does not have a standard Java mapping.  <p>
         *
         * This value is simply the expected class name, regardless of whether
         * HSQLDB, the specific HSQLDB distribution instance or the hosting JVM
         * actually provide or support such implementations. That is, as of a
         * specific release, HSQLDB may not yet provide such an implementation
         * or may not automatically map to it or may not support it as a table
         * column type, the version of java.sql may not define the interface to
         * implement and the HSQLDB jar may not contain the implementation
         * classes, even if they are defined _in the corresponding release
         * and build options and are supported under the hosting JVM's java.sql
         * version.<p>
         *
         * @return the fully-qualified name of the HSQLDB-provided java.sql
         *    interface implementation class whose instances would
         *    be manufactured by HSQLDB to retrieve column values of
         *    this type, given that the type does not have a standard Java
         *    mapping and regardless of whether a class with the indicated
         *    name is actually implemented or available on the class path
         */
        public string getCstMapClsName()
        {

            switch (type)
            {

                default:
                    return null;
            }
        }

        // NOTES:
        // From recent usability testing, this patch and the corresponding patch in
        // jdbcResultSetMetaData together provide better compatibility with existing
        // tools than through the previous method of dynamically scanning each result
        // _in jdbcResultSetMetaData.  This is especially true given that many tools use
        // the display size to set their public max # of characters reserved for
        // result columns at said position. Also, since adding implementation of
        // ResultSetMetaData retreived from PreparedStatement's getMetaData method,
        // there exists the case where there is no data to scan _in order to determine
        // an approximation.  Finally, since for plain old Statement objects the only
        // way to get metadata is to execute the query and since the scan approximation
        // can vary from one execution to the next, it turns _out it's much "safer" and
        // more usable _in a tool setting to simply indicate a large but expected
        // acceptable number of characters, rather than report either a number generally
        // too large to handle or a number too small to hold the actual expected maximum
        // number of characters for result colums of CHAR or VARCHAR types

        /**
         * Retrieves the maximum length that a string representation of
         * the type may have. <p>
         *
         * The calculation follows these rules: <p>
         *
         * <ol>
         * <li>Long character and datetime types:<p>
         *
         *     The maximum length/precision, repectively.<p>
         *
         * <li>CHAR and VARCHAR types: <p>
         *
         *      The value of the system property hsqldb.max_xxxchar_display_size
         *      or the magic value 32766 (0x7FFE) (tested usable/accepted by most
         *      tools and compatible with assumptions made by java.io read/write
         *      UTF) when the system property is not defined or is not accessible,
         *      due to security constraints. <p>
         *
         * <li>Number types: <p>
         *
         *     The max precision, plus the length of the negation character (1),
         *     plus (if applicable) the maximum number of characters that may
         *     occupy the exponent character sequence. <p>
         *
         * <li>bool/BIT types: <p>
         *
         *     The length of the character sequence "false" (5), the longer of the
         *     two bool value string representations. <p>
         *
         * <li>All remaining types: <p>
         *
         *     The result of whatever calculation must be performed to determine
         *     the maximum length of the type's string representation. If the
         *     maximum display size is unknown, unknowable or inapplicable, then
         *     zero is returned. <p>
         *
         * </ol>
         *
         * @return the maximum length that a string representation of
         *      the type may have, or zero (0) if unknown or unknowable
         */
        public int getMaxDisplaySize()
        {
            return Types.getMaxDisplaySize(type);
        }

        /**
         * Retrieves the data type, as an Integer. <p>
         *
         * @return the data type, as an Integer.
         */
        public int getDataType()
        {
            return (type);
        }

        /**
         * Retrieves the data subtype, as an Integer. <p>
         *
         * @return the data subtype, as an Integer
         */
        public int getDataTypeSub()
        {
            return (typeSub);
        }

        /**
         * Retrieves the implied or single permitted scale for exact numeric
         * types, when no scale is declared or no scale declaration is
         * permitted. <p>
         *
         * @return the implied or single permitted scale for exact numeric
         *    types, when no scale is declared or no scale declaration
         *    is permitted
         */
        public int? getDefaultScale()
        {

            switch (type)
            {

                case Types.SQL_BIGINT:
                case Types.SQL_INTEGER:
                case Types.SQL_SMALLINT:
                case Types.TINYINT:
                    return (0);

                default:
                    return null;
            }
        }

        /**
         * Retrieves null (not implemented). <p>
         *
         * @return null (not implemented)
         */
        public int? getIntervalPrecision()
        {
            return null;
        }

        /**
         * Retrieves the character(s) prefixing a literal of this type. <p>
         *
         * @return the character(s) prefixing a literal of this type.
         */
        public string getLiteralPrefix()
        {

            switch (type)
            {

                case Types.SQL_BINARY:
                case Types.SQL_BLOB:
                case Types.SQL_CHAR:
                case Types.SQL_NCHAR:
                case Types.SQL_CLOB:
                case Types.SQL_VARBINARY:
                case Types.SQL_VARCHAR:
                case Types.SQL_NVARCHAR:
                    return "'";

                case Types.SQL_DATALINK:
                    return "'";    // hypothetically: "{url '";

                case Types.SQL_DATE:
                    return "'";    // or JDBC escape: "{d '";

                case Types.OTHER:
                    return "'";    // hypothetically: "{o '"; or new "pkg.cls"(...)

                case Types.SQL_TIME_WITH_TIME_ZONE:
                case Types.SQL_TIME:
                    return "'";    // or JDBC escape: "{t '";

                case Types.SQL_TIMESTAMP_WITH_TIME_ZONE:
                case Types.SQL_TIMESTAMP:
                    return "'";    // or JDBC escape: "{ts '";

                case Types.SQL_XML:
                    return "'";    // hypothetically: "{xml '";

                default:
                    return null;
            }
        }

        /**
         * Retrieves the character(s) terminating a literal of this type. <p>
         *
         * @return the character(s) terminating a literal of this type
         */
        public string getLiteralSuffix()
        {

            switch (type)
            {

                case Types.SQL_BINARY:
                case Types.SQL_BLOB:
                case Types.SQL_CHAR:
                case Types.SQL_NCHAR:
                case Types.SQL_CLOB:
                case Types.NCLOB:
                case Types.SQL_LONGVARBINARY:
                case Types.SQL_VARBINARY:
                case Types.SQL_VARCHAR:
                case Types.SQL_NVARCHAR:
                    return "'";

                case Types.SQL_DATALINK:
                case Types.SQL_DATE:
                case Types.OTHER:
                case Types.SQL_TIME:
                case Types.SQL_TIME_WITH_TIME_ZONE:
                case Types.SQL_TIMESTAMP:
                case Types.SQL_TIMESTAMP_WITH_TIME_ZONE:
                case Types.SQL_XML:
                    return "'";    

                default:
                    return null;

            }
        }

        /**
         * Retrieves a localized representation of the type's name, for human
         * consumption only. <p>
         *
         * @return a localized representation of the type's name
         */
        public string getLocalName()
        {

            if (!locale_set)
            {
                setLocale(System.Globalization.CultureInfo.CurrentCulture);
            }

            string key = this.getTypeName();

            return BundleHandler.getString(hnd_local_names, key);
        }

        /**
         * Retrieves the maximum Short.MaxValue bounded scale supported
         * for the type. <p>
         *
         * @return the maximum Short.MaxValue bounded scale supported
         *    for the type
         */
        public int? getMaxScale()
        {

            switch (type)
            {

                case Types.SQL_BIGINT:
                case Types.SQL_DATE:
                case Types.SQL_TIME_WITH_TIME_ZONE:
                case Types.SQL_TIME:
                case Types.SQL_INTEGER:
                case Types.SQL_SMALLINT:
                case Types.TINYINT:
                    return (0);

                case Types.SQL_TIMESTAMP_WITH_TIME_ZONE:
                case Types.SQL_TIMESTAMP:
                    return (6);

                case Types.SQL_DECIMAL:
                case Types.SQL_NUMERIC:
                    return (short.MaxValue);

                case Types.SQL_FLOAT:
                case Types.SQL_REAL:
                case Types.SQL_DOUBLE:
                    return (306);

                default:
                    return null;
            }
        }

        /**
         * Retrieves the maximum int.MaxValue bounded scale supported for
         * the type. <p>
         *
         * @return the maximum int.MaxValue bounded scale supported
         *    for the type
         */
        public int? getMaxScaleAct()
        {

            switch (type)
            {

                case Types.SQL_DECIMAL:
                case Types.SQL_NUMERIC:
                    return (int.MaxValue);

                default:
                    return getMaxScale();
            }
        }

        /**
         * Retrieves the minumum Short.MinValue bounded scale supported for
         * the type. <p>
         *
         * @return the minumum Short.MinValue bounded scale
         *    supported for the type
         */
        public int? getMinScale()
        {

            switch (type)
            {

                case Types.SQL_BIGINT:
                case Types.SQL_DATE:
                case Types.SQL_INTEGER:
                case Types.SQL_SMALLINT:
                case Types.SQL_TIME:
                case Types.SQL_TIME_WITH_TIME_ZONE:
                case Types.SQL_TIMESTAMP:
                case Types.SQL_TIMESTAMP_WITH_TIME_ZONE:
                case Types.TINYINT:
                case Types.SQL_DECIMAL:
                case Types.SQL_NUMERIC:
                    return (0);

                case Types.SQL_FLOAT:
                case Types.SQL_REAL:
                case Types.SQL_DOUBLE:
                    return (-324);

                default:
                    return null;
            }
        }

        /**
         * Retrieves the minumum int.MinValue bounded scale supported
         * for the type. <p>
         *
         * @return the minumum int.MinValue bounded scale supported
         *    for the type
         */
        public int? getMinScaleAct()
        {
            return getMinScale();
        }

        /**
         * Retrieves the DatabaseMetaData default nullability code for
         * the type. <p>
         *
         * @return the DatabaseMetaData nullability code for the type.
         */
        public int getNullability()
        {
            return (columnNullable);
        }

        /**
         * Retrieves the number base which is to be used to interpret the value
         * reported by getPrecision(). <p>
         *
         * @return the number base which is to be used to interpret the
         *    value reported by getPrecision()
         */
        public int? getNumPrecRadix()
        {

            switch (type)
            {

                case Types.SQL_BIGINT:
                case Types.SQL_DECIMAL:
                case Types.SQL_INTEGER:
                case Types.SQL_NUMERIC:
                case Types.SQL_SMALLINT:
                    return (10);

                case Types.SQL_FLOAT:
                case Types.SQL_DOUBLE:
                case Types.SQL_REAL:
                    return (2);

                default:
                    return null;
            }
        }

        /**
         * Retrieves the maximum int.MaxValue bounded length or precision for
         * the type. <p>
         *
         * @return the maximum int.MaxValue bounded length or
         *    precision for the type
         */
        public int? getPrecision()
        {

            int? p = Types.getPrecision(type);

            return p == 0 ? null
                          : (p);
        }

        /**
         * Retrieves the maximum long.MaxValue bounded length or precision for
         * the type. <p>
         *
         * @return the maximum long.MaxValue bounded length or
         *    precision for the type
         */
        public long? getPrecisionAct()
        {

            int? temp = getPrecision();

            if (temp == null)
            {
                return (long.MaxValue);
            }
            else
            {
                return (temp);
            }
        }

        /**
         * Retrieves the localized remarks (if any) on the type. <p>
         *
         * @return the localized remarks on the type.
         */
        public string getRemarks()
        {

            if (!locale_set)
            {
                setLocale(System.Globalization.CultureInfo.CurrentCulture);
            }

            string key = this.getTypeName();

            return BundleHandler.getString(hnd_remarks, key);
        }

        /**
         * Retrieves the DatabaseMetaData searchability code for the type. <p>
         *
         * @return the DatabaseMetaData searchability code for the type
         */
        public int getSearchability()
        {
            return Types.isSearchable(type) ? (typeSearchable)
                                            : (typePredNone);
        }

        /**
         * Retrieves the SQL CLI data type code for the type. <p>
         *
         * @return the SQL CLI data type code for the type
         */
        public int? getSqlDataType()
        {

            // values from SQL200n SQL CLI spec, or DITypes (which _in turn borrows
            // first from java.sql.Types and then SQL200n SQL CLI spec) if there
            // was no corresponding value _in SQL CLI
            switch (type)
            {

                case Types.SQL_ARRAY:
                    return (Types.SQL_ARRAY);        // SQL_ARRAY

                case Types.SQL_BIGINT:
                    return (Types.SQL_BIGINT);       // SQL_BIGINT

                case Types.SQL_BINARY:
                    return (Types.SQL_BLOB);         // fredt- was SQL_BIT_VARYING

                case Types.SQL_BOOLEAN:
                    return (Types.SQL_BOOLEAN);      // SQL_bool

                case Types.SQL_BLOB:
                    return (Types.SQL_BLOB);         // SQL_BLOB

                case Types.SQL_CHAR:
                    return (Types.SQL_CHAR);         // SQL_CHAR

                case Types.SQL_CLOB:
                    return (Types.SQL_CLOB);         // SQL_CLOB

                case Types.SQL_DATALINK:
                    return (Types.SQL_DATALINK);     // SQL_DATALINK

                case Types.SQL_DATE:

                    // NO:  This is the _concise_ code, whereas what we want to
                    //      return here is the Data Type Code column value from
                    //      Table 38 _in the SQL 200n FCD.  This method is used
                    //      by DatabaseInformationMain to list the sql type
                    //      column _in the SYSTEM_TYPEINFO table, which is specified
                    //      by JDBC as the sql data type code, not the concise code.
                    //      That is why there is a sql datetime sub column
                    //      specified as well.
                    // return  (Types.SQL_DATE);         // fredt - was SQL_DATETIME
                    return (Types.SQL_DATETIME);

                case Types.SQL_DECIMAL:
                    return (Types.SQL_DECIMAL);      // SQL_DECIMAL

                case Types.DISTINCT:
                    return (Types.SQL_UDT);          // SQL_UDT

                case Types.SQL_DOUBLE:
                    return (Types.SQL_DOUBLE);       // SQL_DOUBLE

                case Types.SQL_FLOAT:
                    return (Types.SQL_FLOAT);        // SQL_FLOAT

                case Types.SQL_INTEGER:
                    return (Types.SQL_INTEGER);      // SQL_INTEGER

                case Types.CSHARP_OBJECT:
                    return (Types.CSHARP_OBJECT);      // N/A - maybe SQL_UDT?

                case Types.LONGVARBINARY:
                    return (Types.SQL_BLOB);         // was SQL_BIT_VARYING

                case Types.LONGVARCHAR:
                    return (Types.SQL_CLOB);         //

                case Types.SQL_ALL_TYPES:
                    return (Types.SQL_ALL_TYPES);    // SQL_ALL_TYPES

                case Types.SQL_NUMERIC:
                    return (Types.SQL_NUMERIC);      // SQL_NUMERIC

                case Types.OTHER:
                    return (Types.OTHER);            // N/A - maybe SQL_UDT?

                case Types.SQL_REAL:
                    return (Types.SQL_REAL);         // SQL_REAL

                case Types.SQL_REF:
                    return (Types.SQL_REF);          // SQL_REF

                case Types.SQL_SMALLINT:
                    return (Types.SQL_SMALLINT);     // SQL_SMALLINTEGER

                case Types.STRUCT:
                    return (Types.SQL_UDT);          // SQL_UDT

                case Types.SQL_TIME:

                    // NO:  This is the _concise_ code, whereas what we want to
                    //      return here is the Data Type Code column value from
                    //      Table 38 _in the SQL 200n FCD.  This method is used
                    //      by DatabaseInformationMain to list the sql type
                    //      column _in the SYSTEM_TYPEINFO table, which is specified
                    //      by JDBC as the sql data type code, not the concise code.
                    //      That is why there is a sql datetime sub column
                    //      specified as well.
                    // return  (Types.SQL_TIME);         // fredt - was SQL_DATETIME
                    return (Types.SQL_DATETIME);

                case Types.SQL_TIMESTAMP:

                    // NO:  This is the _concise_ code, whereas what we want to
                    //      return here is the Data Type Code column value from
                    //      Table 38 _in the SQL CLI 200n FCD.  This method is used
                    //      by DatabaseInformationMain to list the sql type
                    //      column _in the SYSTEM_TYPEINFO table, which is specified
                    //      by JDBC as the sql data type code, not the concise code.
                    //      That is why there is a sql datetime sub column
                    //      specified as well.
                    // return  (Types.SQL_TIMESTAMP);    // fredt - was SQL_DATETIME
                    return (Types.SQL_DATETIME);

                case Types.TINYINT:
                    return (Types.TINYINT);          // N/A

                case Types.VARBINARY:
                    return (Types.SQL_BLOB);         // SQL_BIT_VARYING

                case Types.SQL_VARCHAR:
                    return (Types.SQL_VARCHAR);      // SQL_VARCHAR

                case Types.SQL_NVARCHAR:
                    return (Types.SQL_NVARCHAR);      // SQL_VARCHAR

                case Types.SQL_XML:
                    return (Types.SQL_XML);          // SQL_XML

                default:
                    return null;
            }
        }

        /**
         * Retrieves the SQL CLI datetime subcode for the type. <p>
         *
         * @return the SQL CLI datetime subcode for the type
         */
        public int? getSqlDateTimeSub()
        {

            switch (type)
            {

                case Types.SQL_DATE:
                    return (1);

                case Types.SQL_TIME:
                    return (2);

                case Types.SQL_TIMESTAMP:
                    return (3);

                default:
                    return null;
            }
        }

        /**
         * Retrieve the fully qualified name of the recommended standard Java
         * primitive, class or java.sql interface mapping for the type. <p>
         *
         * @return the fully qualified name of the recommended standard Java
         *    primitive, class or java.sql interface mapping for
         *    the type
         */
        public string getStdMapClsName()
        {

            switch (type)
            {
                case Types.SQL_ARRAY:
                    return "System.Array";

                case Types.SQL_BIGINT:
                    return "long";

                case Types.SQL_BINARY:
                case Types.SQL_LONGVARBINARY:
                case Types.SQL_VARBINARY:
                    return "byte[]";

                case Types.SQL_BOOLEAN:
                    return "bool";

                case Types.SQL_BLOB:
                    return "byte[]";

                case Types.SQL_CHAR:
                case Types.SQL_NCHAR:
                case Types.SQL_VARCHAR:
                case Types.SQL_NVARCHAR:
                    return "string";

                case Types.SQL_CLOB:
                    return "Char[]";

                case Types.NCLOB:
                    return "Char[]";

                case Types.SQL_DATALINK:
                    return "System.Uri";

                case Types.SQL_DATE:
                    return "DateTime";

                case Types.SQL_DECIMAL:
                case Types.SQL_NUMERIC:
                    return "decimal";

                case Types.DISTINCT:
                    return "string";

                case Types.CSHARP_OBJECT:
                case Types.OTHER:
                    return "object";

                case Types.SQL_XML:
                    return "string";

                case Types.SQL_REAL:
                    return "float";

                case Types.SQL_FLOAT:
                case Types.SQL_DOUBLE:
                    return "double";

                case Types.SQL_INTEGER:
                    return "int";

                case Types.SQL_ALL_TYPES:
                    return "System.Void";

                case Types.SQL_REF:
                    return "object";

                case Types.SQL_SMALLINT:
                    return "short";

                case Types.STRUCT:
                    return "System.ValueType";

                case Types.SQL_TIME:
                    return "DateTime";

                case Types.SQL_TIMESTAMP:
                    return "DateTime";

                case Types.TINYINT:
                    return "byte";

                case Types.ROWID:
                    return "System.Guid";

                default:
                    return null;
            }
        }

        /**
         * Retrieves the data type as an int. <p>
         *
         * @return the data type as an int
         */
        public int getTypeCode()
        {
            return type;
        }

        /**
         * Retrieves the canonical data type name HSQLDB associates with
         * the type.  <p>
         *
         * This typically matches the designated JDBC name, with one or
         * two exceptions. <p>
         *
         * @return the canonical data type name HSQLDB associates with the type
         */
        public string getTypeName()
        {

            return typeSub == Types.TYPE_SUB_IGNORECASE
                   ? Types.getTypeName(Types.VARCHAR_IGNORECASE)
                   : Types.getTypeName(type);
        }

        /**
         * Retrieves the HSQLDB data subtype as an int. <p>
         *
         * @return the HSQLDB data subtype as an int
         */
        public int getTypeSub()
        {
            return this.typeSub;
        }

        /**
         * Retrieves whether the type can be an IDENTITY type. <p>
         *
         * @return whether the type can be an IDENTITY type.
         */
        public bool? isAutoIncrement()
        {

            switch (type)
            {

                case Types.SQL_DECIMAL:
                case Types.SQL_DOUBLE:
                case Types.SQL_FLOAT:
                case Types.SQL_NUMERIC:
                case Types.SQL_REAL:
                case Types.SQL_SMALLINT:
                    return false;

                case Types.SQL_BIGINT:
                case Types.SQL_INTEGER:
                    return true;

                default:
                    return null;
            }
        }

        /**
         * Retrieves whether the type is case-sensitive _in collations and
         * comparisons. <p>
         *
         * @return whether the type is case-sensitive _in collations and
         *    comparisons.
         */
        public bool? isCaseSensitive()
        {

            return typeSub == Types.TYPE_SUB_IGNORECASE ? false
                                                        : Types.isCaseSensitive(type);
        }

        /**
         * Retrieves whether, under the current release, class path and hosting
         * JVM, HSQLDB supports storing this type _in table columns. <p>
         *
         * This value also typically represents whether HSQLDB supports retrieving
         * values of this type _in the columns of ResultSets.
         * @return whether, under the current release, class path
         *    and hosting JVM, HSQLDB supports storing this
         *    type _in table columns
         */
        public bool isColStClsSupported()
        {

            return (type == Types.SQL_ALL_TYPES ? true : getColStClsName()
                                                           != null);
        }

        /**
         * Retrieves whether values of this type have a fixed precision and
         * scale. <p>
         *
         * @return whether values of this type have a fixed
         *    precision and scale.
         */
        public bool? isFixedPrecisionScale()
        {

            switch (type)
            {

                case Types.SQL_BIGINT:
                case Types.SQL_DECIMAL:
                case Types.SQL_DOUBLE:
                case Types.SQL_FLOAT:
                case Types.SQL_INTEGER:
                case Types.SQL_NUMERIC:
                case Types.SQL_REAL:
                case Types.SQL_SMALLINT:
                case Types.TINYINT:
                    return false;

                default:
                    return null;
            }
        }

        /**
         * Retrieve whether the fully qualified name reported by getStdMapClsName()
         * is supported as a jdbcResultSet.getXXX return type under the current
         * HSQLDB release, class path and hosting JVM. <p>
         *
         * @return whether the fully qualified name reported by getStdMapClsName()
         * is supported as a jdbcResultSet.getXXX return type under the current
         * HSQLDB release, class path and hosting JVM.
         */
        public bool isStdMapClsSupported()
        {
            // its ok to use Class.forName here instead of nameSpace.classForName,
            // because all standard map classes are loaded by the boot loader
            bool isSup = true;
         
            return isSup;
        }

        /**
         * Retrieves whether, under the current release, class path and
         * hosting JVM, HSQLDB supports passing or receiving this type as
         * the value of a procedure column. <p>
         *
         * @return whether, under the current release, class path and
         *    hosting JVM, HSQLDB supports passing or receiving
         *    this type as the value of a procedure column.
         */
        public bool isSupportedAsPCol()
        {
            switch (type)
            {

                case Types.SQL_ALL_TYPES:           // - for void return type
                case Types.CSHARP_OBJECT:    // - for Connection as first parm and

                //   Object for return type
                case Types.ARRAY:          // - for Object[] row of Trigger.fire()
                    return true;

                default:
                    return isSupportedAsTCol();
            }
        }

        /**
         * Retrieves whether, under the current release, class path and
         * hosting JVM, HSQLDB supports this as the type of a table
         * column. <p>
         *
         * @return whether, under the current release, class path
         *    and hosting JVM, HSQLDB supports this type
         *    as the values of a table column
         */
        public bool isSupportedAsTCol()
        {

            return SqlType.isSupportedSQLType(type);
        }

        /**
         * Retrieves whether values of this type are unsigned. <p>
         *
         * @return whether values of this type are unsigned
         */
        public bool? isUnsignedAttribute()
        {
            return Types.isUnsignedAttribute(type);
        }

        /**
         * Assigns the Locale object used to retrieve this object's
         * resource bundle dependent values. <p>
         *
         * @param l the Locale object used to retrieve this object's resource
         *      bundle dependent values
         */
        public void setLocale(CultureInfo l)
        {

            if (l == null)
            {
                hnd_create_params = hnd_local_names = hnd_remarks = -1;
                locale_set = false;

                return;
            }

            CultureInfo oldLocale;

            lock (typeof(BundleHandler))
            {
                oldLocale = BundleHandler.getLocale();

                BundleHandler.setLocale(l);

                hnd_create_params =
                    BundleHandler.getBundleHandle("data-type-create-parameters",
                                                  null);
                hnd_local_names = BundleHandler.getBundleHandle("data-type-names",
                        null);
                hnd_remarks = BundleHandler.getBundleHandle("data-type-remarks",
                        null);

                BundleHandler.setLocale(oldLocale);

                locale_set = true;
            }
        }

        /**
         * Assigns the SQL data type code on which this object is to report. <p>
         *
         * @param type the SQL data type code on which this object is to report
         */
        public void setTypeCode(int type)
        {
            this.type = type;
        }

        /**
         * Assigns the HSQLDB data subtype code on which this object is
         * to report. <p>
         *
         * @param typeSub the HSQLDB data subtype code on which this object
         *      is to report
         */
        public void setTypeSub(int typeSub)
        {
            this.typeSub = typeSub;
        }
    }
}
